// Effective C++ 条款40：明智而审慎地使用多重继承

// 详细解释
// 多重继承的定义与挑战
// 多重继承（Multiple Inheritance，MI）是指一个类同时从多个基类继承的能力。虽然这提供了强大的设计工具，但也带来了一系列复杂性：
// 1.命名冲突：当多个基类有同名成员时
// 2.菱形继承：当一个类间接继承同一个基类多次时
// 3.复杂的构造和析构顺序：多个基类的初始化和清理顺序
// 4.可维护性挑战：增加了代码理解和维护的难度

// 菱形继承问题
// 菱形继承是多重继承中最常见的问题之一：
class File
{
public:
    std::string filename;
};

class InputFile : public File
{
};
class OutputFile : public File
{
};

class IOFile : public InputFile, public OutputFile
{
};
// 在这个例子中，IOFile继承了File两次，导致：
// IOFile有两个filename成员
// 访问filename变得歧义：iofile.filename会导致编译错误

// 虚继承解决方案
// 虚继承是解决菱形继承问题的机制：
class File
{ /* ... */
};
class InputFile : virtual public File
{ /* ... */
};
class OutputFile : virtual public File
{ /* ... */
};
class IOFile : public InputFile, public OutputFile
{ /* ... */
};
// 使用虚继承后：
// IOFile只包含一个File子对象
// 可以无歧义地访问File的成员：iofile.filename

// 虚继承的成本
// 虽然虚继承解决了菱形继承问题，但它带来了额外成本：
// 1.内存开销：虚基类指针和更复杂的对象布局
// 2.性能开销：访问虚基类成员需要间接寻址
// 3.初始化复杂性：最派生类负责虚基类的初始化

// 多重继承的实际应用
// 1. 接口继承与实现继承结合
// 一种常见的MI模式是同时继承接口和实现：
// 接口类
class IPerson
{
public:
    virtual ~IPerson() = default;
    virtual std::string name() const = 0;
    virtual std::string birthDate() const = 0;
};

// 实现类
class PersonImpl
{
protected:
    std::string theName;
    std::string theBirthDate;

public:
    explicit PersonImpl(const std::string &name, const std::string &birthDate)
        : theName(name), theBirthDate(birthDate) {}
};

// 使用多重继承
class CPerson : public IPerson, private PersonImpl
{
public:
    explicit CPerson(const std::string &name, const std::string &birthDate)
        : PersonImpl(name, birthDate) {}

    // 实现接口
    std::string name() const override { return theName; }
    std::string birthDate() const override { return theBirthDate; }
};

// 2. Mixin继承
// Mixin是提供特定功能的类，通过多重继承组合这些功能：
class Printable
{
public:
    virtual void print() const = 0;
    virtual ~Printable() = default;
};

class Serializable
{
public:
    virtual void serialize(std::ostream &os) const = 0;
    virtual ~Serializable() = default;
};

class Object : public Printable, public Serializable
{
    // 实现两个接口
};

// 3. 空基类优化与策略组合
// 多重继承空基类可以组合多种策略而不增加对象大小：
template <typename T>
class NoThrowMovePolicy
{ /* ... */
};

template <typename T>
class FastCopyPolicy
{ /* ... */
};

template <typename T>
class OptimizedContainer : private NoThrowMovePolicy<T>,
                           private FastCopyPolicy<T>
{
    // 组合两种优化策略
};
// 1. 避免菱形继承
// 如果可能，设计类层次结构时避免菱形继承。如果无法避免，使用虚继承，但要意识到其成本。

// 2. 考虑替代方案
// 在使用多重继承前，考虑其他设计模式：
//      组合而非继承
//      单一继承加接口实现
//      委托模式

// 3. 遵循设计原则
//      优先使用公共继承表示接口
//      优先使用私有继承表示实现细节
//      保持基类简单，特别是虚基类

// 4. 处理歧义
// 当多个基类有同名成员时，显式指定要使用的版本：
class Derived : public Base1, public Base2
{
public:
    void ambiguousMethod()
    {
        Base1::method(); // 显式指定使用Base1的版本
    }
};

// 总结
// 条款40告诉我们，多重继承是一个强大但复杂的工具，应该"明智而审慎地使用"。具体来说：
// 1.多重继承可以解决某些设计问题，特别是接口与实现分离的场景
// 2.了解并避免多重继承的陷阱，特别是菱形继承
// 3.当使用虚继承时，要意识到其性能和复杂性成本
// 4.考虑替代设计模式，只在多重继承确实是最佳解决方案时使用它
// 多重继承不是万能的，也不是万恶的，它是C++工具箱中的一个专用工具，在正确的场景下使用可以创建优雅而强大的设计。